package com.atguigu.userprofile.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.userprofile.bean.TagCondition;
import com.atguigu.userprofile.bean.TagInfo;
import com.atguigu.userprofile.bean.UserGroup;
import com.atguigu.userprofile.constants.ConstCodes;
import com.atguigu.userprofile.mapper.UserGroupMapper;
import com.atguigu.userprofile.service.TagInfoService;
import com.atguigu.userprofile.service.UserGroupService;
import com.atguigu.userprofile.utils.RedisUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhangchen
 * @since 2021-05-04
 */
@Service
@Slf4j
@DS("mysql")
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {


    @Autowired
    TagInfoService tagInfoService;

    @Override
    public void saveUserGroupInfo(UserGroup userGroup) {
        // 1.1 条件list 转为json存储
        // 1.2 条件中的中文提取出来用于显示，存储
        // 1.3  创建时间

        List<TagCondition> tagConditions = userGroup.getTagConditions();
        String tagConditionjsonStr = JSON.toJSONString(tagConditions);
        userGroup.setConditionJsonStr(tagConditionjsonStr);

        String conditionComment = userGroup.conditionJsonToComment();
        userGroup.setConditionComment(conditionComment);

        userGroup.setCreateTime(new Date());

        saveOrUpdate(userGroup);
    }





    @Override
    public void genUserGroupUs(UserGroup userGroup) {
        // 调用getInsertSelectSQL  的到最终sql
        String insertSelectSQL = getInsertSelectSQL(  userGroup);
        // 执行sql语句  放到mapper层执行
        System.out.println(insertSelectSQL);
        super.baseMapper.insertBitmap(insertSelectSQL);

    }

    @Override
    public void saveUserGroupToRedis(UserGroup userGroup) {
        Jedis jedis = RedisUtil.getJedis();
        //1 读取clickhouse中的计算结果
        //把bitmap读取到java的一个list里去

        //新1 获得bitmapAndSQL
        String bitmapAndSQL = getBitmapAndSQL(userGroup);
        String selectSQL = "select   arrayJoin(  bitmapToArray(" + bitmapAndSQL + "))";
        List<String> uidList = super.baseMapper.selectBitmapToList(selectSQL);

//        List<String> uidList = super.baseMapper.getBitmapToList(userGroup.getId().toString());
//        System.out.println(uidList);

        //2  list写入redis
        // type?   set     key ?  user_group:[user_group_id]     value ? uids    field/score? 无
        // 写入api sadd   读取api sismember  smembers
        //  过期？ 不用过期
        String userGroupKey="user_group:"+userGroup.getId();

        String[] arr=new String[]{};
        String[] uids = uidList.toArray(arr);

        jedis.del(userGroupKey);  //考虑更新问题 ，提前清理旧数据
        jedis.sadd(userGroupKey,uids);

        //人数写入对象
        userGroup.setUserGroupNum(uids.length+0L);

        jedis.close();
    }



    //select bitmapCardinality(
    //    bitmapAnd(
    //        bitmapAnd (
    //         (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_gender' and tag_value = '女'  and dt='2020-06-14')
    //         ,
    //         (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_agegroup' and tag_value in ( '80后','90后'  ) and dt='2020-06-14')
    //      )
    //       ,(select    groupBitmapMergeState(us)  from user_tag_value_decimal where tag_code ='tg_behavior_order_amount_7d' and tag_value <= 1000  and dt='2020-06-14')
    //      ))
    //  )
    @Override
    public Long evaluateUserGroupNum(UserGroup userGroup) {

        String bitmapAndSQL = getBitmapAndSQL(userGroup);
        String sql ="select bitmapCardinality("+ bitmapAndSQL+")";
        Long userGroupNum = super.baseMapper.selectUserGroupNum(sql);

        return userGroupNum;
    }

    @Override
    public UserGroup refreshUserGroup(String userGroupId, String busiDate) {
        //1  根据id 取得分群的基本信息
        UserGroup userGroup = super.getById(userGroupId);
        String conditionJsonStr = userGroup.getConditionJsonStr();
        List<TagCondition> tagConditionList = JSON.parseArray(conditionJsonStr, TagCondition.class);
        userGroup.setTagConditions(tagConditionList);

        userGroup.setBusiDate(busiDate);


        //2  更新分群
        //2.1   删除旧的人群包
        this.baseMapper.deleteUserGroup(userGroupId);
        //2.2   写入新的人群包
        genUserGroupUs(  userGroup);

        return userGroup;
    }




    //insert into user_group
    //select   bitmapAnd(
    //   bitmapAnd (
    //    (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_gender' and tag_value = '女'  and dt='2020-06-14')
    //     ,
    //    (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_agegroup' and tag_value in ( '80后','90后'  ) and dt='2020-06-14')
    //  )
    //  ,(select    groupBitmapMergeState(us)  from user_tag_value_decimal where tag_code ='tg_behavior_order_amount_7d' and tag_value <= 1000  and dt='2020-06-14')
    // ))
    public String getInsertSelectSQL(UserGroup userGroup){
        //调用getBitmapAndSQL 拼上insert select 的开头
        String bitmapAndSQL = getBitmapAndSQL(userGroup);
        String insertSQL = "insert into user_group select '"+userGroup.getId()+"'," + bitmapAndSQL;

        return  insertSQL;
    }


    // bitmapAnd(
    //        bitmapAnd (
    //         (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_gender' and tag_value = '女'  and dt='2020-06-14')
    //         ,
    //         (select   groupBitmapMergeState(us)  from user_tag_value_string  where tag_code ='tg_person_base_agegroup' and tag_value in ( '80后','90后'  ) and dt='2020-06-14')
    //      )
    //       ,(select    groupBitmapMergeState(us)  from user_tag_value_decimal where tag_code ='tg_behavior_order_amount_7d' and tag_value <= 1000  and dt='2020-06-14')
    //      ))
    private String getBitmapAndSQL(UserGroup userGroup){
        //循环调用getSubquerySQL 拼接得到bitmapAndSQL
        List<TagCondition> tagConditionList = userGroup.getTagConditions();
        Map<String,TagInfo> tagInfoMap=tagInfoService.getTagInfoMapWithCode();

        StringBuilder bitmapAndSQLBuilder=new StringBuilder();

        for (TagCondition tagCondition : tagConditionList) {
            String subquerySQL = getSubquerySQL(tagCondition, userGroup.getBusiDate(), tagInfoMap);
            if(bitmapAndSQLBuilder.length()==0){
                bitmapAndSQLBuilder.append("("+subquerySQL+")");
            }else{
                bitmapAndSQLBuilder.insert(0,"bitmapAnd(").append(",(").append(subquerySQL).append("))");
            }

        }
        return  bitmapAndSQLBuilder.toString();
    }


    //根据一个条件，生成一个子查询sql
    //select   groupBitmapMergeState(us)  from user_tag_value_string
    // where tag_code ='tg_person_base_gender' and tag_value = '女'  and dt='2020-06-14'
    // 要素分析：
    // 1 表名 ：如何得知条件应该查那张表，通过tagcode 查询mysql 获得 tagValueType值类型 ，判断应该查哪张表 ？
      //   多少个条件就要查多少次数据库吗？ 查询一次让多个条件共用查询结果 一次io操作+多次内存操作？ 以什么形式保存在内存中 k-v hashmap
    // 2 tag_code 从 tagCondition 取tagcode
    // 3比较符 ： 用operator  转换为操作符
    // 4 tag_value :   有可能一个 ，也可能多个  ，多个需要 逗号拼接
               //   可能数字  可能字符串    数字不加单引 字符串要加单引    依据 tagValueType值类型
               //   操作符为in 或 not in   需要加小括号
    // 5 dt  要从busiDate获得

    private String getSubquerySQL(TagCondition tagCondition,String busiDate,Map<String,TagInfo> tagInfoMap){
       // tagcode
        String tagCode = tagCondition.getTagCode();
        TagInfo tagInfo = tagInfoMap.get(tagCode);
        String tagValueType = tagInfo.getTagValueType();
      //tableName
        String tableName="";
        if (ConstCodes.TAG_VALUE_TYPE_STRING.equals(tagValueType)  ){
            tableName="user_tag_value_string";
        } else if (ConstCodes.TAG_VALUE_TYPE_DECIMAL.equals(tagValueType)  ){
            tableName="user_tag_value_decimal";
        } else  if (ConstCodes.TAG_VALUE_TYPE_LONG.equals(tagValueType)  ){
            tableName="user_tag_value_long";
        } else   if (ConstCodes.TAG_VALUE_TYPE_DATE.equals(tagValueType)  ){
            tableName="user_tag_value_date";
        }
     // operator
        String operator = tagCondition.getOperator();
        String conditionOperator = getConditionOperator(operator);
     //tag_value :
        List<String> tagValues = tagCondition.getTagValues();
        String tagValueSQL="";
        if (ConstCodes.TAG_VALUE_TYPE_STRING.equals(tagValueType) ||ConstCodes.TAG_VALUE_TYPE_DATE.equals(tagValueType)  ){
         // 加单引
              tagValueSQL = "'"+StringUtils.join(tagValues, "','")+"'";
        } else {
            //不加单引
            tagValueSQL = StringUtils.join(tagValues, ",");
        }
        if(operator.equals("in")||operator.equals("nin")){
            tagValueSQL="("+tagValueSQL+")";
        }
        // dt
        String dt=busiDate;

        String subquerySQL="select   groupBitmapMergeState(us)  " +
                " from  " +tableName+
                " where tag_code ='"+tagCode.toLowerCase()+"' " +
                " and tag_value "+conditionOperator+" " +tagValueSQL+
                " and dt='"+dt+"'" ;


        return subquerySQL;
    }


    private  String getConditionOperator(String operator){
        switch (operator){
            case "eq":
                return "=";
            case "lte":
                return "<=";
            case "gte":
                return ">=";
            case "lt":
                return "<";
            case "gt":
                return ">";
            case "neq":
                return "<>";
            case "in":
                return "in";
            case "nin":
                return "not in";
        }
        throw  new RuntimeException("操作符不正确");
    }

}
